﻿/// <reference path="../../../fly/fly.js" />
/// <reference path="../../fly.ui.js" />

fly.regPlugin("gridpanel", function ($) {
    var ui = $.ui, $e = $.Event, $c = $.collection, dh = ui.DomHelper
    function Grid(config) {
        arguments.callee.$base.apply(this, arguments)
        this.onPreRender(this.initHeader)
        this.cellCss || (this.cellCss = "f-" + this.$ctype + "-c");
        this.onAfterBind([this.initFirstCell, this.initFirstRow]);
        this.onCreateFrame(function () {
            this.ellipsisContent && this.body && this.body.addClass("f-" + this.$ctype + "-" + ui.util.ellipsisCss)
            this.bindEvents()
            this.showHeader || this.headerEl && this.headerEl.outer.hide()
        });
        this.onRender(function () {
            if (this.store)
                this.bind()
        }, this);

        if (this.store)
            this.setStore(this.store)
    }

    /*	#C path:fly.ui.grid.GridPanel
    通过网格形式在客户端浏览数据，可以配合分页控件使用
    @base   :fly.ui.Panel
    @config :JSON 初始化配置
    */
    ui.grid.GridPanel = new $.Class(
    {

        base: ui.Panel,
        overrides: ui.IDataBound,
        constructor: Grid,
        /*Boolean 是否自动加载数据*/
        autoLoad: true,
        /*Object 当前排序规则*/
        sortInfo: null,
        dataColumns: [],
        columns: null,
        /*JSON  配置Gird行事件，如：
        rowEvents:{
        click:function(row,cell,grid){
        alert(row.id)
        },
        keyup:function(row,cell,grid){
        alert($event.keyCode+" "+ row.id)
        }
        }
        事件将接收三个参数：行、单元格和GridPanel，通常情况下事件中this和第三个参数一样，代表当前GridPanel对象
        */
        rowEvents: null,
        /*Boolean 显示列头*/
        showHeader: true,
        /*Boolean  是否启用列头排序,默认 true*/
        headerSortAble: true,
        /*Boolean 当内容超出宽带时显示省略号*/
        ellipsisContent: true,
        applyUniqueCss: true,
        baseCss: "f-grid",
        /*String 列头样式*/
        headerCss: "",
        /*String 行样式*/
        rowCss: "",
        tableCss: '',
        /*String 行TR元素样式*/
        trCss: 'f-grid-tr',
        /*String 交替行样式*/
        altRowCss: "f-grid-row-alt",
        /*Int/Function 为整数时，表示每隔指定行数显示一交替行，为函数时，当函数返回true显示交替行，函数接受两个参数，行和行的索引*/
        altRowBy: 2,
        loadingCss: 'f-loading-32 f-show',
        domFrame: { el: { wrap: ["tbar", "headerEl", { body: "table" }, "bbar"]} },

        colFormat: null, //'<COL class="{colCss} f-{$ctype}-col-{dataIndex}" />',
        createCols: function () {
            if (this.colFormat) {
                var htmls = this.columns.select(function (o, i) {
                    return this.colFormat.format(i, this, o)
                }, this)
                return htmls.join("")
            }
        },
        initDataColumn: function (c, i) {
            if (!(c instanceof ui.grid.Column)) {
                var ac = new ui.grid.Column(c)
                if (c instanceof ui.grid.RowSelectionModel) {
                    c.column = ac
                    if (!this.sm)
                        this.sm = c
                    ac.join = ui.grid.Column.prototype.join
                }
                c = ac;
            }
            c.join(this, i)
            return c
        },
        initHeader: function () {
            if (!(this.header instanceof ui.grid.Header))
                this.header = new ui.grid.Header(this.header, this.columns)
            this.header.join(this)
            this.dataColumns = this.header.getDataColumns()
        },

        createHeaderEl: function () {
            return this.header.createHeader()
        },
        /*String 单元格模板*/
        cellFormat: null,
        /*String 行模板*/
        rowFormat: null,
        /*Array<fly.ui.grid.Row> 所有行*/
        rows: null,
        /*绑定记录
        @records:Array<Object> 要绑定的记录
        @option :JSON   选项
        @return :Array<fly.ui.grid.Row> 创建的行*/
        bindRecords: function (records, option) {
            if (!records)
                return
            var me = this
            var p = this.table.dom.parentNode, next = this.table.dom.nextSibling;
            p.removeChild(this.table.dom)

            this.rows.each(function (r) {
                r.destroy()
            });

            this.rows.clear()

            option = option || {}
            this.dataColumns.each(function (c) {
                if ($.is(c, ui.grid.RowNumberer))
                    c.current = option.start == null ? c.start : option.start
            })
            this.records = records;
            var rows = [];
            for (var i = 0; i < records.length; i++) {
                var row = new ui.grid.Row(this, records[i])
                rows.push(row.buildUI())
            }

            this.rows.add.apply(this.rows, rows);
            this.altRowCss && this.onAfterBind(this.applyAltRowCss)
            if (!this.store.remoteSort && (this.sortDir || this.sortBy))
                this.sort(this.sortDir, this.sortBy)
            else
                for (var i = 0; i < rows.length; i++)
                    this.rowsContainer.dom.appendChild(rows[i].el.dom);
            this.checkEmpty()
            this.fire("bindrecords", null, rows);

            next ? dh.before(next, this.table.dom) : p.appendChild(this.table.dom)

            setTimeout(function () {
                me.table.fire("sizechange")
            }, 1)

            return rows
        },
        /*Object 当没有记录时,绑定到空行的数据*/
        emptyRecord: null,
        /*Object 当没有记录时,空行的样式*/
        emptyRowCss: 'f-grid-emptyTR',
        /*fly.ui.grid.Row 当没有记录时,生成的空行*/
        emptyRow: null,

        checkEmpty: function () {
            if (this.table.dom.rows.length > 0) {
                this.emptyRow && this.emptyRow.el.remove()
            }
            else {
                if (!this.emptyRow) {
                    this.emptyRow = new ui.grid.Row(this, this.emptyRecord)
                    this.emptyRow.isEmpty = true
                    this.emptyRow.buildUI().tr.addClass(this.emptyRowCss)
                }
                this.rowsContainer.append(this.emptyRow.el)
            }
        },
        /*GirdPanel外层元素模板*/
        elFormat: '<DIV class="f-panel f-{$ctype} {css}"></DIV>',

        /*String 单元格模板*/
        tableFormat: '<TABLE border=0 cellpadding=0 cellspacing=0 class="f-{$ctype}-t {tableCss}" >{createCols()}</TABLE>',

        /*创建Table 
        @return :fly.ui.Element 创建的Table元素*/
        createTable: function () {
            this.table = this.tableFormat.toElement(this)
            this.cols = this.table.find("col");
            this.cols.each(function (c, i) {
                this.dataColumns[i].col = c;
            }, this);
            this.createRowsContainer()

            if (this.headerEl) {
                var resize = function () {
                    var me = this
                    var bDom = me.body.dom
                    var w = bDom.offsetWidth
                    me.headerEl.width(me.table.dom.offsetWidth);
                    me.hasYScroll = bDom.scrollHeight > bDom.clientHeight
                    if (me.hasYScroll)
                        w -= ui.util.scrollWidth

                    me.wrap[me.hasYScroll ? "addClass" : "removeClass"](me.baseCss + "-y-scroll")

                    me.headerEl.wrap.dom.style.width = Math.max(w, 0) + "px"
                }

                this.table.on("sizechange", resize, this)
                this.body && this.body.on("sizechange", resize, this)

                this.body.onScroll(function () {
                    this.headerEl.wrap.dom.scrollLeft = this.body.dom.scrollLeft;
                }, this);
            }

            return this.table
        },
        getLoading: function (option) {
            return { css: this.loadingCss, box: this.getAjaxStatusBox.bind(this) }
        },
        getAjaxStatusBox: function (helper, status, isEnd) {
            if (!this.loadingBox) {
                this.loadingBox = $('<div class="f-hidden f-grid-ajax-status"></div>')
                this.loadingBox.prependTo(this.body || this.table[0].parentNode)
            }
            return this.loadingBox;
        },
        bindEvents: function () {
            var me = this
            var res = me.rowEvents
            for (var k in res) {
                (function (k) {
                    me.table.on(k, function () {
                        var el = $event.target
                        var row = me.getOwnerRow(el);
                        if (row == null)
                            return
                        var td = el
                        while (td && (td.parentNode != row.tr.dom))
                            td = td.parentNode;
                        row && res[k].call(me, row, row.cells[td ? td.cellIndex : -1], me)
                    })
                })(k)
            }
        },
        createRowsContainer: function () {
            this.rowsContainer = new ui.Element(document.createElement("tbody"));
            this.table.dom.appendChild(this.rowsContainer.dom)
            return this.rowsContainer
        },

        /*GridPanel wrap层格式化模板 */
        wrapFormat: '<DIV  class="f-{$ctype}-wrap" ></DIV>',

        createStyle: function () {
            var me = this
            if (this.rowHeight != null && this.rowHeight > 0) {
                var style = "height:" + this.rowHeight + (/^[\d\s]+$/.test(this.rowHeight) ? "px;" : ";")
                ui.Style.createCssRule(this.styleSheet, "." + this.uniqueCss + " .f-grid-body TR", style)
            }

            $.each(this.dataColumns, function (i) {
                this.createRule(me.styleSheet)
                this.setWidth(this.width);
            });

        },
        /* #E 在GridPanel呈现前触发
        @return :Boolean    返回false将取消GridPanel呈现 */
        onPreRender: $e.createEventFn("prerender", function () {
            if (this.fire("prerender") !== false) {
                this.rows = new $c.MapList();
                this.sm && this.sm.join(this)

                this.styleSheet = ui.Style.defaultSheet()
                this.onCreateFrame(function () {
                    this.createStyle();
                    this.canBind = true;
                }, this);
            }
            else
                return false
        }),

        /*设置GridPanel高
        @height :Int 高
        @return :this   */
        setHeight: function (height) {
            this.outer.un("sizechange", this.reHeight)
            this.outer.height(height)
            if (height != "" && height != null && height != "auto") {
                this.outer.on("sizechange", this.reHeight, this)
                this.reHeight()
                setTimeout(this.reHeight.bind(this), 200)
            }
            return this
        },
        reHeight: function () {
            if (this.body) {
                var oSize = this.outer.offset();
                var bDom = this.body.dom
                var wrapW = this.wrap.outerHeight() - this.wrap.contentHeight()
                var d = this.wrap.dom.scrollHeight - bDom.offsetHeight - bDom.offsetTop
                var h = Math.max(this.outer.contentHeight() - bDom.offsetTop - d - wrapW, 0)
                if (h + "px" != this.body.css("height"))
                    this.body.height(h);
            }
            this.applyScroll()
        },
        /*设置GridPanel宽
        @width :Int 宽
        @return :this   */
        setWidth: function (width) {
            (this.el || this.outer).width(width)
            if (this.body) {
                this.applyScroll()
            }
            return this
        },
        applyScroll: function () {
        },

        applyAltRowCss: function () {
            var by = this.altRowBy, css = this.altRowCss, rs = this.rows
            var isFun = $.isFun(by)
            for (var i = 0; i < this.rows.length; i++)
                rs[i].tr[(isFun ? this.altRowBy(rs[i], i) : (i + 1) % by) ? "removeClass" : "addClass"](css);
        },

        initFirstCell: function () {
            var cells = this.firstCells || (this.firstCells = [])
            var css = this.firstCellCss || "f-" + this.$ctype + "-c-first";
            if (cells.length && cells[0].colIndex != 0) {
                for (var i = 0, l = cells.length; i < l; i++) {
                    var cell = cells[i]
                    cell.className = cell.className.replace(css, "")
                }
                cells.splice(0, cells.length);
            }
            var rows = this.rows
            for (var i = 0, l = rows.length; i < l; i++) {
                var c = rows[i].cells[0].el.dom;
                cells.push(c);
                c.className += " " + css;
            }
            if (this.headerEl) {
                var hFist = (this.headerEl.dom.rows[1] || this.headerEl.dom.rows[0]).cells[0]
                hFist.className += " " + css;
                cells.push(hFist);
            }
        },

        initFirstRow: function () {
            var dom, fRow = this.firstRow, css = this.firstRowCss || "f-" + this.$ctype + "-r-first";
            if (fRow && fRow != this.rows[0])
                fRow.tr && fRow.tr.removeClass(css);

            if (this.firstRow = fRow = this.rows[0])
                fRow.tr && fRow.tr.addClass(css);
        },
        /*排序
        @dir    :String 排序方向，ASC 或者 DESC
        @by     :fly.ui.grid.Column 排序的列
        @return :this   */
        sort: function (dir, by) {
            var rows = this.rows, cont = this.rowsContainer.dom
            this.sortDir = dir
            this.sortBy = by;
            if (!this.store.remoteSort || by.remoteSort == false) {
                var compare = by.sortBy;
                if (!$.isFun(compare)) {
                    var p = by.sortBy == null ? by.dataIndex : by.sortBy
                    compare = function (a, b) {
                        var va = a.record[p], vb = b.record[p]
                        va = va === undefined ? null : va
                        vb = vb === undefined ? null : vb
                        return va == vb ? 0 : va > vb ? 1 : -1;
                    }
                }

                $c.IList.order.call(rows, dir, compare);

                var p = this.table.dom.parentNode;
                p && p.removeChild(this.table.dom)

                try {
                    for (var i = 0; i < rows.length; i++)
                        cont.removeChild(rows[i].el.dom)
                } catch (e) { }

                for (var i = 0; i < rows.length; i++)
                    cont.appendChild(rows[i].el.dom)

                p && p.appendChild(this.table.dom)
                this.initFirstRow();
                this.altRowCss && this.applyAltRowCss()
                this.fire("sort");
            }
            else {
                this.bind({
                    sortDir: dir,
                    sortBy: by.sortBy == null || $.isFun(by.sortBy) ? by.dataIndex : by.sortBy
                })
            }
            return this;
        },
        /* #E 在GridPanel排序时触发*/
        onSort: $e.createEventFn("sort"),
        /*获取元素所在行 
        @el :HtmlElement    Html元素
        @return :fly.ui.grid.Row 元素所在行*/
        getOwnerRow: function (el) {
            var id = ui.grid.Row.getOwnerRowId(el)
            return this.rows.dataMap[id];
        },
        /*获取元素所在单元格 
        @el :HtmlElement    Html元素
        @return :fly.ui.grid.Cell 元素所在单元格*/
        getOwnerCell: function (el) {
            var row = this.getOwnerRow(el)
            if (!row)
                return null;
            while (el && el.parentNode != row.tr.dom)
                el = el.parentNode
            return row.cells[el.cellIndex]
        },
        destroys: ['rows']
    })
    $.Component.Mgr.regType('grid', ui.grid.GridPanel)

    ui.grid.Header = $.Class({
        constructor: function (config, columns) {
            config && $.extend(this, config)
            columns && (this.columns = columns)
        },
        columns: null,
        level: 1,
        join: function (grid) {
            this.grid = grid
        },
        /*获取数据行
        @return: Array<fly.ui.grid.Column> */
        getDataColumns: function () {
            var me = this, dCols = [], l = 1
            function h(c, i, all) {
                var isParent = $.isArray(c.columns) && c.columns.length
                if (!isParent)
                    dCols.push(c = all[i] = me.grid.initDataColumn(c, dCols.length))
                c.isDataColumn = !isParent

                if (!c.colSpan)
                    c.colSpan = 1

                c.parent = this.p
                if (isParent) {
                    c.columns.each(h, { l: this.l + 1, p: c })
                    c.colSpan = c.columns.sum("o=>o.colSpan")
                }
                else {
                    l = Math.max(l, this.l)
                    var p = c.parent, rowSpan = this.rowSpan || 1
                    while (p) {
                        p._rowSpan = Math.max(p._rowSpan || 0, rowSpan)
                        rowSpan += p.rowSpan || 1
                        p = p.parent
                    }
                }
            }
            this.columns.each(h, { l: l })
            this.level = l;
            return dCols
        },
        /*String 列头单元格格式化模板*/
        cellFormat: '<TD class="{grid.baseCss}-hc" ><span class="{grid.baseCss}-col-resize"><div></div></span><span _class="{grid.baseCss}-col-sort-ico"><div></div></span><span class="{grid.baseCss}-hc-text"></span></TD>',
        /*String 列头格式化模板*/
        headerFormat: '<DIV class="{grid.baseCss}-h-outer {grid.headerCss}" ><DIV class={grid.baseCss}-h-wrap ><TABLE border=0 cellpadding=0 cellspacing=0  class="{grid.baseCss}-h"><TBODY>{createTRs()}</TBODY></TABLE></DIV></DIV>',
        createTRs: function () {
            var str = "";
            var i = this.level
            while (i > -1) {
                str += '<TR class="f-grid-h-tr f-grid-h-tr-' + i + '" ></TR>'
                i--
            }
            return str;
        },

        createHeader: function () {
            var me = this
            var outer = this.headerFormat.toElement(this)
            this.el = new ui.Element(outer.dom.firstChild.firstChild)
            this.el.wrap = new ui.Element(outer.dom.firstChild)
            this.el.outer = outer;
            var rows = me.el.dom.rows, rowD = me.level > 1 ? 1 : 0

            if (rowD) {
                this.grid.dataColumns.each(function (c, i) {
                    var td = document.createElement("td")
                    td.className = "f-" + me.grid.$ctype + "-col-" + i
                    rows[0].appendChild(td)
                })
                rows[0].className += " f-grid-h-tr-empty"
            }
            else
                me.el.dom.deleteRow(0)

            me.el.dom.rows[rowD].className += " f-grid-h-tr-first"

            function h(c) {
                var tr = rows[this.ri + rowD]
                var rowSpan = c.rowSpan
                if (rowSpan == null)
                    rowSpan = me.level - (c._rowSpan || 0) - this.ri
                var cell = me.createHeaderCell(c)
                cell.dom.rowSpan = rowSpan
                cell.dom.colSpan = c.colSpan || 1
                cell.appendTo(tr)
                c.columns && c.columns.each(h, { ri: this.ri + rowSpan })
            }
            this.columns.each(h, { ri: 0, rs: 0 })
            return this.el
        },
        createHeaderCell: function (col) {
            var me = this, grid = me.grid
            var el = (this.cellFormat || col.headerCellFormat).toElement({ grid: grid, header: me, column: col })

            col.headerTextEl = new ui.Element("[class*='-hc-text']", el.dom);
            col.headerCell = el

            col.resizeEl = new ui.Element("[class*='-col-resize']", el.dom);
            if (col.resizable == false || grid.columnResizable == false)
                col.resizeEl.remove()
            else {
                col.resizeHelper = new ui.DragHelper({
                    handle: col.resizeEl,
                    changeCursor: false,
                    dragY: false,
                    listeners: {
                        start: function () {
                            var mark = $('<div class="f-' + grid.$ctype + '-resize-mark"></div>');

                            var wRect = grid.wrap.rect(), cRect = this.handle.rect()
                            mark.left(cRect.left - wRect.left + cRect.width - 1)
                            mark.height(grid.body.dom.offsetHeight)
                            grid.body.before(mark)
                            this.elements.merge(mark)
                        },
                        stop: function () {
                            this.elements.each(function (o) {
                                o.remove()
                            });
                            this.elements.clear()
                            var dx = this.context.dx
                            if (col.isDataColumn)
                                col.addWidth(dx, true)
                            else {
                                var c = col
                                while (c.columns && c.columns.length)
                                    c = c.columns.last()
                                if (c && c.addWidth)
                                    c.addWidth(dx, true)
                            }
                        }
                    }
                });
            }

            if (col.isDataColumn) {
                el.dom.className += " f-grid-hc-col"

                if (grid.headerSortAble != false && (col.sortAble == true || (col.sortAble == "auto" && col.dataIndex != null))) {
                    col.sortEl = new ui.Element("[_class*='-col-sort-ico']", el.dom);
                    col.sortEl.cssPart = col.sortEl.attr("_class")
                    col.sortEl.addClass(col.sortEl.cssPart);

                    el.onClick(function () {
                        if (ui.DragHelper.started)
                            return;
                        if (/input|button/i.test($.$event.target.nodeName))
                            return;

                        if ([$event.target].is(".disableSort") || [$event.target].is(".disableSort *"))
                            return

                        col.sortDir = col.sortDir == "ASC" && grid.sortBy == col ? "DESC" : "ASC"

                        var css = col.sortEl.cssPart, ascCss = css + "-asc", descCss = css + "-desc"
                        col.sortEl.removeClass(col.sortDir == "ASC" ? descCss : ascCss).addClass(col.sortDir == "ASC" ? ascCss : descCss)
                        var pBy = grid.sortBy
                        if (pBy != col && $.is(pBy, ui.grid.Column))
                            pBy.sortEl.removeClass(ascCss + " " + descCss);
                        grid.sort(col.sortDir, col);
                    })
                }
            }

            col.headerCss && el.addClass(col.headerCss);
            col.headerStyle && (el.dom.style.cssText += ";" + col.headerStyle)

            if (col.headerRenderer) {
                var c = col.headerRenderer(col.header, col.headerTextEl)
                if (c != null && c != "")
                    col.headerTextEl.dom.innerHTML = c
            }
            else if (col.header != null && col.header !== '') {
                col.headerTextEl.dom.innerHTML = col.header
            }

            col.colCss && (el.dom.className += " " + col.colCss)
            return col.headerCell = el
        }
    })

    /*	#C path:fly.ui.grid.Row
    GridPanel 中的行
    @grid   :所属GridPanel
    @record :为行绑定的记录
    */
    ui.grid.Row = $.Class({
        constructor: function (grid, record) {
            this.cells = [];
            this.grid = grid
            this.record = record || {}
            this.id = this.record[grid.store.idProperty];
            if (this.id == null || this.id instanceof Function)
                this.id = Math.random().toString().substr(2);
        },
        isEmpty: false,
        /*Object    行的id，通过GridPanel Store的idProperty属性指定的属性名，在record中获取，默认为record的id属性 */
        id: null,
        /*HtmlElement   行的Html元素，通常情况下是tr元素*/
        el: null,
        /*HtmlElement   行的TR元素*/
        tr: null,
        buildUI: function () {
            if (this.grid.rowFormat) {
                this.el = this.grid.rowFormat.toElement(this)
                this.tr = this.el.dom.nodeName == "TBODY" ? new ui.Element(this.el.dom.firstChild) : this.el;
            }
            else {
                this.el = new ui.Element(document.createElement("tr"));
                this.tr = this.el;
            }

            this.el.dom.setAttribute("f-row-id", this.id)
            if (this.grid.rowCss)
                this.el.dom.className = (this.el.dom.className || '') + " " + this.grid.rowCss
            if (this.grid.trCss)
                this.tr.dom.className = (this.tr.dom.className || '') + " " + this.grid.trCss
            var cols = this.grid.dataColumns, rec = this.record
            for (var i = 0; i < cols.length; i++) {
                var c = new ui.grid.Cell(this, cols[i], this.record)
                this.cells[i] = c
            }
            return this
        },
        destroy: function () {
            if (this.tr) {
                this.tr.un()
                this.tr.destroy()
            }

            if (this.el && this.el != this.tr) {
                this.el.un()
                this.el.destroy()
            }

            $.each(this.cells, function (c) {
                c.destroy()
            })
            this.el = this.tr = this.cells = this.grid = this.record = this.checkbox = null
        }
    })
    ui.grid.Row.toggleIsKeep = function (el) {
        if (!el.childNodes.length)
            return
        for (var i = 0; i < el.childNodes.length; i++) {
            var c = el.childNodes[0]
            if (c.nodeName != 'INPUT' || c.className.indexOf('f-node-cbox') < 0)
                return
        }
        return true
    }
    /*静态方法，获取Html元素所在的行Id
    @el :HtmlElement    Html元素
    @return:    Object 所在行Id */
    fly.ui.grid.Row.getOwnerRowId = function (el) {
        var id
        while (el && el.getAttribute && (id = el.getAttribute("f-row-id")) == null)
            el = el.parentNode;
        return id
    }

    /*	#C path:fly.ui.grid.Cell
    GridPanel 中的单元格
    @row    :所属行
    @column   :所属列
    @record :为行绑定的记录，等于row.record
    */
    ui.grid.Cell = $.Class({
        constructor: function (row, column, record) {
            this.row = row
            this.grid = row.grid
            this.column = column
            this.record = record
            this.buildUI()
            if (!row.isEmpty)
                this.render();
            this.row.tr.dom.appendChild(this.el.dom);
        },
        /*fly.ui.Element   为单元格创建的Html元素，通常为TD元素*/
        el: null,
        buildUI: function () {
            var temp = this.column.template || this.grid.cellFormat;
            if (temp)
                this.el = temp.toElement(this.grid, this.record)
            else
                this.el = new ui.Element(document.createElement("td"));

            this.el.dom.className += " " + this.grid.cellCss + " " + this.column.cellCss
        },
        /*呈现单元格
        @return:undefined */
        render: function () {
            var v, col = this.column
            if (col.dataIndex != null)
                this.value = v = this.record[col.dataIndex]
            if (col.renderer) {
                var c = col.renderer(v, this)
                if (c === undefined)
                    return;
                this.value = v = c;
            }

            if (col.format)
                this.value = v = col.format.$format(v);

            this.el.dom[col.contentProperty] = v == null ? "" : v
        },
        destroy: function () {
            this.el && this.el.un()
            this.row = this.grid = this.column = this.record = this.el = this.value = null
        }
    })

    /*	#C path:fly.ui.grid.Column
    GridPanel 中的列
    @config :JSON   列初始化配置
    @base   :fly.Component
    */
    ui.grid.Column = $.Class({
        base: $.Component,
        constructor: function (config) {
            if (config != null && !$.isObject(config))
                config = { dataIndex: config }

            config && $.extend(this, config)
        },
        join: function (grid, index) {
            this.grid = grid
            this.header == null && (this.header = this.dataIndex);
            this.index = index;
            this.colCss = "f-" + grid.$ctype + "-col-" + index
            this.cellCss = this.colCss + (this.css ? " " + this.css : "")
            this.setWidth(this.width)
        },
        /*Boolean   只读,默认false*/
        readOnly: false,
        /*Object 列头*/
        header: null,
        /*Int 列索引*/
        index: 0,
        /*String/Int 从绑定记录(record)中获取单元格值的属性名*/
        dataIndex: null,
        /*String 应用到该列的css样式*/
        css: "",
        /*Boolean  是否可以排序,默认 true*/
        sortAble: true,
        /*Function  用来配合排序的比较函数*/
        sortBy: null,
        /*String 该列单元格值显示到Html元素中的属性名，默认为：innerHTML ，如果要显示普通文本，设置为 innerText */
        contentProperty: "innerHTML",
        createRule: function (sheet) {
            if (this.rule) return this
            this.rule = ui.Style.createCssRule(sheet, "." + this.grid.uniqueCss + " ." + this.colCss, "")
            if (this.style)
                ui.Style.createCssRule(sheet, "." + this.grid.uniqueCss + " .f-grid-body ." + this.colCss, this.style)
        },
        /*设置列宽
        @width  :Int 列宽
        @return :this */
        setWidth: function (width) {
            this.width = ui.Style.checkValue("width", width)
            if (this.rule && this.width != null)
                this.rule.style.width = this.width
            return this
        },
        /*增加宽度
        @width  :Int 要增加的宽度
        @return :this */
        addWidth: function (width, smart) {
            if (width) {
                var tWidth = Math.max(10, this.grid.headerEl.dom.offsetWidth + width)
                var col = this
                while (col) {
                    var w = col.headerCell.dom.offsetWidth + width
                    if (smart && w < 10) {
                        col.setWidth(10)
                        width = w - 10
                        col = this.grid.dataColumns[col.index - 1]
                    }
                    else {
                        col.setWidth(Math.max(0, w))
                        break;
                    }
                }

                this.grid.table.width(tWidth)
                this.grid.headerEl.width(tWidth)
            }
            return this
        }
    })

    /*	#C path:fly.ui.grid.RowNumberer
    GridPanel 行编号列
    @config :JSON   初始化配置
    @base   :fly.ui.grid.Column
    */
    ui.grid.RowNumberer = $.Class(
    {
        base: ui.grid.Column,
        constructor: function () {
            arguments.callee.$base.apply(this, arguments)
            this.current = this.start
        },
        width: 23,
        /*Boolean   只读,默认true*/
        readOnly: true,
        id: 'numberer',
        sortBy: function (a, b) {
            var va = a.rowNumber, vb = b.rowNumber
            return va == vb ? 0 : va > vb ? 1 : -1;
        },
        /*Int  编号开始*/
        start: 1,
        /*Int  编号增量*/
        seed: 1,
        next: function () {
            this.current += this.seed
        },
        renderer: function (v, cell) {
            var c = this.current;
            this.next();
            return cell.row.rowNumber = c;
        }
    });

    /*	#C path:fly.ui.grid.RowSelectionModel
    GridPanel 行选择模型
    @config :JSON   初始化配置
    @base   :fly.ui.BaseSelectionModel
    */
    ui.grid.RowSelectionModel = $.Class(
    {
        base: ui.BaseSelectionModel,
        /*Boolean 默认选择列不用远程排序*/
        remoteSort: false,
        /*Boolean   只读,默认true*/
        readOnly: true,
        selectedCss: "f-grid-r-selected",
        getItems: function () {
            return this.control.rows
        },
        toggleIsKeep: ui.grid.Row.toggleIsKeep,
        getOwnerItemId: ui.grid.Row.getOwnerRowId,
        join: function (grid) {
            ui.grid.RowSelectionModel.$base.prototype.join.apply(this, arguments)
        },
        elName: "tr"
    })

    /*	#C path:fly.ui.grid.CheckboxSelectionModel
    GridPanel 行Checkbox选择模型
    @config :JSON   初始化配置
    @base   :fly.ui.grid.RowSelectionModel
    */
    var gcsm = ui.grid.CheckboxSelectionModel = $.Class(
    {
        base: ui.grid.RowSelectionModel,
        /*默认列宽25*/
        width: 25,
        /*应用到checkbox的样式*/
        boxCss: "",
        join: function (grid) {
            gcsm.$base.prototype.join.call(this, grid)
            if (this.column)
                this.column.boxCss = 'f-' + this.control.$ctype + '-r-cbox f-node-cbox'
            return this
        },
        /*列头呈现函数
        @value:Object 列头显示内容
        @el :   HtmlElement 列头的单元格Html元素*/
        headerRenderer: function (v, el) {
            var sm = this.sm || this.grid.sm
            if (sm.singleSelect) return
            el.dom.innerHTML = '<input type=checkbox unselectable="on"  />' + (v == null ? "" : v);
            this.headerBox = new ui.Element(el.dom.firstChild)
            this.headerBox.onClick(this.headerClick, sm, this.headerBox);
            this.headerBox.onContextMenu(this.headRightClick, sm, this.headerBox);
        },
        /*单元格呈现函数
        @value:Object 单元格的值
        @cell :   fly.ui.grid.Cell 呈现的单元格 */
        renderer: function (v, cell) {
            cell.el.dom.innerHTML = '<input type=checkbox unselectable="on" class="' + this.boxCss + '" />'
            var el = cell.row.checkbox = new ui.Element(cell.el.dom.firstChild);
            el.onClick(this.boxClick, this.grid.sm || (this.grid.tree && this.grid.tree.root.ownerControl.sm), el, cell.row)
            return
        },
        /*checkbox单击执行的函数
        @el:fly.ui.Element checkbox元素
        @row :   当前行 
        @return :  false 取消当前事件继续执行*/
        boxClick: function (el, row) {
            var me = this, is = el.dom.checked;
            setTimeout(function () {
                me.select(row, is)
                el.dom.blur();
            })
            return false
        },
        /*列头checkbox右击时执行的函数
        @el:fly.ui.Element checkbox元素
        @return :  false 取消当前事件继续执行*/
        headRightClick: function (el) {
            this.toggleAll()
            return false
        },
        /*列头checkbox单击时执行的函数
        @el:fly.ui.Element checkbox元素*/
        headerClick: function (el) {
            el.dom.checked ? this.selectAll() : this.clearSelections()
        },
        elName: "tr"
    });



    /*	#C path:fly.ui.grid.plugins.TreeGrid
    用于GridPanel的，树形视图插件
    @config :JSON   初始化配置
    @base   :fly.Component
    */
    ui.grid.plugins.TreeGrid = $.Class(
    {
        base: $.Component,
        overrides: ui.IControlPlugin,
        constructor: function () {
            arguments.callee.$base.apply(this, arguments)
            if (!$.is(this.sm, ui.tree.CheckboxSelectionModel)) {
                this.sm = new ui.tree.CheckboxSelectionModel(this.sm)
                this.sm.fireByText = false
            }
        },

        listeners:
        {
            join: function () {
                var grid = this.ownerControl
                grid.onPreCreateFrame(function () {
                    var c = this.ownerControl, col = this.treeColumn
                    if (!$.is(this.treeColumn, ui.grid.Column))
                        col = this.treeColumn = c.dataColumns[col]

                    if (col.renderer != this.renderer) {
                        this.oldRenderer = col.renderer;
                        col.renderer = this.renderer;
                    }

                    if (this.showCheckbox && col.headerRenderer != this.headerRenderer)
                        col.headerRenderer = this.headerRenderer.bind(this)

                    c.tree = this;
                    c.css = (c.css || "") + " f-grid-tree"
                    col.css = (col.css || "") + " f-grid-tree-cell"
                    c.rowFormat = this.rowFormat = '<tbody><tr ></tr></tbody>';
                    c.createRowsContainer = this.createRowsContainer.bind(this);
                    c.getParams = this.getParams
                    this.ownerNode = c.ownerNode
                    this.isRoot = !this.ownerNode
                    this.childrenProperty = c.store.childrenProperty
                    if (this.isRoot) {
                        this.root = this
                        this.allNodes = new $c.MapList()
                        this.items = new $c.MapList();
                        if (this.sm && !this.sm.joined) {
                            this.sm.join(this);
                            this.sm.getOwnerItemId = ui.grid.Row.getOwnerRowId
                            this.sm.toggleIsKeep = ui.grid.Row.toggleIsKeep
                            this.sm.getItems = this.getAllNodes.bind(this)
                        }

                        if (c.sm)
                            c.sm.getItems = c.getAllRows = this.getAllRows.bind(this);
                        else
                            c.sm = this.sm;
                    }
                    else {
                        c.getLoading = this.getLoading.bind(this)
                        this.items = this.ownerNode.items;
                        this.root = this.ownerNode.tree.root;
                        if (this.root.sortChildren) {
                            this.root.ownerControl.onSort(function () {
                                var rc = this.root.ownerControl;
                                c.sort(rc.sortDir, rc.sortBy);
                            }, this)
                        }
                    }
                    c.onPreBind(this.reBuildQueryOption, this);
                    c.onSort(this.reSetAllRows, this).onAfterBind(this.reSetAllRows, this);

                    this.checkBoxHtml = this.showCheckbox ? '<input type=checkbox class="f-node-cbox" unselectable=on />' : ""
                    this.contentProperty == null && (this.contentProperty = col.contentProperty)
                }, this)
            }
        },
        /*在加载节点数据前，重新构造查询选项
        @option:    JSON    原查询选项*/
        reBuildQueryOption: function (option) {
            if (!this.isRoot) {
                if (option.nodeId == null)
                    option.nodeId = this.ownerNode.id
                if (!option.record)
                    option.record = this.ownerNode.record
            }
        },

        /*Boolean 排序时，同时排序子节点*/
        sortChildren: true,
        /*Boolean 为节点显示checkbox元素*/
        showCheckbox: true,
        /*String/Int 从绑定记录(record)中获取text的属性名*/
        textProperty: "text",
        /*String 该列单元格值显示到Html元素中的属性名，默认为：innerText ，如果要显示Html，设置为 innerHTML */
        contentProperty: null,
        /*Int  树视图所在列索引*/
        treeColumn: 0,
        /*Int  子节点缩进宽度*/
        indent: 10,
        rowFormat: null,
        /*触发节点展开和收缩的事件*/
        toggleEvents: {
            toggleButton: "click",
            icon: "click"
        },
        /*Array<fly.ui.BaseItem> 子节点*/
        items: null,
        /*获取所有行，包含子节点所在行
        @return :Array<fly.ui.grid.Row> 所有行
        */
        getAllRows: function () {
            var t = this.root
            if (t.allRows)
                return t.allRows;
            var allNodes = t.allNodes;
            this.allRows = new $c.MapList();
            if (t.allNodes.length) {
                var rows = t.ownerControl.table.find("tbody['f-row-id']")
                for (var i = 0; i < rows.length; i++) {
                    var node = allNodes.getById(rows[i].getAttribute("f-row-id"))
                    node && this.allRows.add(node.row)
                }
            }
            return this.allRows
        },
        /*获取所有节点，包含所有子节点
        @return :Array<fly.ui.BaseItem> 所有节点
        */
        getAllNodes: function () {
            var t = this.root
            if (t._allNodes) return t._allNodes;

            var rows = this.getAllRows();
            t._allNodes = new $c.MapList();
            for (var i = 0; i < rows.length; i++)
                t._allNodes.add(rows[i].node)

            return t._allNodes
        },
        reSetAllRows: function () {
            this.root.allRows = null
            this.root._allNodes = null
        },
        /*获取节点的查询选项
        @return :JSON*/
        getParams: function () {
            return { nodeId: this.nodeId }
        },
        createRowsContainer: function () {
            return this.ownerControl.rowsContainer = this.ownerControl.table;
        },
        getLoading: function (option) {
            if (this.ownerNode.expanded && this.ownerNode.childGrid.rendered) {
                return { css: this.ownerControl.loadingCss, box: this.ownerControl.getAjaxStatusBox.bind(this.ownerControl) }
            }
            else {
                return { css: 'f-loading-16', box: this.ownerNode.toggleButton }
            }
        },
        headerRenderer: gcsm.prototype.headerRenderer,
        headRightClick: gcsm.prototype.headRightClick,
        headerClick: gcsm.prototype.headerClick,
        renderer: function (v, cell) {
            var row = cell.row, tree = cell.grid.tree

            var node = row.node = new ui.grid.TreeGridNode({
                tree: tree,
                parentNode: tree.ownerNode,
                wrap: row.el,
                el: row.tr,
                elBody: cell.el,
                cell: cell,
                row: row,
                record: row.record,
                id: row.id
            });

            node.buildUI(v)
            tree.items.add(node)
            tree.root.allNodes.add(node)

            row.el.dom.className += " f-node"
            var rowCss = node.leaf ? "f-node-leaf" : "f-node-parent f-node-collapse"
            row.tr.dom.className += " f-node-el " + rowCss
        },

        getChildGridType: function () {
            return this._childGridType || (this._childGridType = ui.grid.ChildGird.create(this.ownerControl))
        }
    });

    $.Component.Mgr.regType("treegrid", ui.grid.plugins.TreeGrid)

    ui.grid.ChildGird = {
        create: function (grid) {
            return $.Class({
                base: grid.constructor
            }).extend(ui.grid.ChildGird)
        }
    }

    /*	#C path:fly.ui.grid.TreeGridNode
    用于GridPanel树形视图插件的节点对象
    @config :JSON   初始化配置
    @base   :fly.ui.BaseItem
    */
    ui.grid.TreeGridNode = $.Class(
    {
        base: ui.BaseItem,

        setText: function (text) {
            if (this.tree.oldRenderer) {
                text = this.tree.oldRenderer.call(this.cell.column, text, this.cell)
                if (text === undefined) {
                    dh.moveContent(this.elBody, this.content);
                    return this;
                }
            }

            if (text != null && text != "" && this.cell.column.format)
                text = this.cell.column.format.$format(text);
            return ui.grid.TreeGridNode.$base.prototype.setText.call(this, text)
        },

        childrenRow: null,

        createChildrenRow: function () {
            var me = this
            var grid = this.tree.ownerControl
            this.childrenRow = new ui.Element('<tr class="f-node-pad"><td colSpan={0} ></td></tr>'.$format(
                grid.dataColumns.length
                ));
            var cols = grid.cols.toHtml()
            var type = this.tree.getChildGridType()
            type.extend({ uniqueNumber: null })
            this.childGrid = new type(
                $.extend(grid.config,
                {
                    createCols: function () { return cols },
                    showHeader: false,
                    domFrame: "table",
                    columns: grid.dataColumns.select("this.clone()"),
                    plugins: grid.plugins.select("this.clone()"),
                    store: grid.store,
                    nodeId: this.row.id,
                    width: "100%",
                    height: "auto",
                    ownerNode: this,
                    tableCss: "f-grid-child-table"
                }))

            this.childGrid.render(this.childrenRow.dom.firstChild);
            this.tree.root.reSetAllRows()
            //            var resize = function () {
            //                me.childGrid.table.width(grid.table.dom.offsetWidth);
            //            }
            //            grid.table.on("sizechange", resize);
            //            resize();
            return this
        },
        showChildPad: function () {
            if (!this.childrenRow) {
                this.createChildrenRow();
                this.wrap.dom.appendChild(this.childrenRow.dom)
            }
            this.childrenRow.show()
            return this
        }
    })


    /*	#C path:fly.ui.grid.plugins.Editing
    使GridPanel可编辑插件
    @config :JSON   初始化配置
    @base   :fly.Component
    */
    var editing = ui.grid.plugins.Editing = $.Class(
    {
        base: $.Component,
        overrides: ui.IControlPlugin,
        /*String 用该事件触发GridPanel编辑操作，默认为 click */
        begin: 'click',
        /*String 编辑模式，row:整行编辑，cell:单元格编辑，默认为整行编辑 */
        editMode: 'row',
        /*fly.ui.Validate 用于GridPanel编辑的验证模块*/
        validator: null,

        constructor: function () {
            arguments.callee.$base.apply(this, arguments)
            this.columns = [];
        },
        /*#E 在GridPanel编辑完成前执行
        @row:fly.ui.grid.Row 当前编辑的行
        @dirty:Object 修改后的记录
        @record:Object 修改前的记录
        @return :Boolean 返回false阻止编辑完成*/
        beforeComplete: null,

        /*#E 在GridPanel编辑完成后执行，请在该事件中执行修改记录的保存操作
        @row:fly.ui.grid.Row 当前编辑的行
        @dirty:Object 修改后的记录
        @record:Object 修改前的记录*/
        afterComplete: null,
        listeners: {
            join: function () {
                var me = this
                var grid = this.grid = this.ownerControl;
                grid.dataColumns.each(function (col) {
                    if (col.readOnly)
                        return;
                    me.columns.push(col)
                    if (!(col.editor instanceof editing.BaseEditor))
                        col.editor = new (editing.Editors[col.editor] || editing.Editors[col.type] || editing.TextEditor)(col.editor)
                    col.editor.join(me, col);
                    if (me.begin == 'load')
                        col.renderer = col.editor.renderer.bind(col.editor)
                })

                this.bindEvents();
            }
        },
        /*开始编辑
        @row:fly.ui.grid.Row 开始编辑的行
        @cell:fly.ui.grid.Cell 开始编辑的列
        @grid:fly.ui.grid.GridPanel 开始编辑的GridPanel*/
        beginEdit: function (row, cell, grid) {
            if (!row || row.editing)
                return

            if (this.lastEditRow && this.completeRow(this.lastEditRow) == false)
                return false

            var lCell, cells = this.editMode == "cell" ? [cell] : row.cells
            cells.each(function (c, i) {
                if (!c.column.editor)
                    return;
                if (cell == true || cell == i)
                    cell = c
                lCell = c;
                c.column.editor.renderer(row.record[c.column.dataIndex], c);
            }, this)

            if (cell == false)
                cell = lCell
            row.editing = true
            this.lastEditRow = row
            if (cell && cell.editorBox)
                cell.column.editor.focus(cell, cell.editorBox)
        },
        /*完成编辑
        @row:fly.ui.grid.Row 当前编辑的行*/
        completeRow: function (row) {
            var dirty = {}
            row.cells.each(function (cell) {
                if (!cell.column.editor)
                    return;
                dirty[cell.column.dataIndex] = cell.column.editor.get(cell)
            })
            rec = $.extend({}, row.record, dirty)

            if ((this.beforeComplete && this.beforeComplete(row, dirty, rec)) === $.CANCEL)
                return false;

            row.cells.each(function (cell) {
                if (!cell.column.editor)
                    return;
                if (cell.column.editor.complete)
                    cell.column.editor.complete(cell)
                else {
                    row.record[cell.column.dataIndex] = dirty[cell.column.dataIndex]
                    cell.column.editor.close(cell)
                }
            })
            this.afterComplete && this.afterComplete(row, dirty, rec);
            row.editing = false

        },
        monitorKeyboard: function () {
            var me = this, grid = this.grid, h
            function siblingRow(r, d) {
                return grid.getOwnerRow(grid.table.dom.rows[r.tr.dom.rowIndex + d])
            }
            grid.table.onKeyDown(function () {
                var code = $event.keyCode, shift = $event.shiftKey;
                if (me.lastEditRow) {
                    if (code == 9 && this.supperTab != false) {
                        clearTimeout(h)
                        h = setTimeout(function () {

                            if (!me.lastEditRow || (document.activeElement && $.DomHelper.contains(me.lastEditRow.el.dom, document.activeElement)))
                                return
                            var row = siblingRow(me.lastEditRow, shift ? -1 : 1)
                            me.beginEdit(row, shift ? false : true, grid)
                        }, 50);
                    }
                    else if (this.supperDirKey != false && (code == 38 || code == 40)) {
                        var row = siblingRow(me.lastEditRow, code == 38 ? -1 : 1), cell = grid.getOwnerCell($event.target)
                        me.beginEdit(row, cell ? cell.column.index : true, grid)
                    }
                }
            });

        },
        bindEvents: function () {
            var grid = this.grid;
            if (this.begin != "load")
                (grid.rowEvents || (grid.rowEvents = {}))[this.begin || 'dblclick'] = this.beginEdit.bind(this);
            else
                this.supperTab = false
            grid.onRender(this.monitorKeyboard.bind(this))
        }
    })

    /*#C path:fly.ui.grid.plugins.Editing.BaseEditor
    可编辑GridPanel中的单元格编辑器基类，其他自定义编辑器需从该类继承
    @config:JSON 初始化配置
    @base:fly.Component*/
    editing.BaseEditor = $.Class({
        base: $.Component,
        join: function (editing, column) {
            this.editing = editing
            this.column = column
        },
        /*在单元格编辑完成时执行，如果需要在单元格编辑完成时执行自定义操作，可以重写该方法
        @cell:fly.ui.grid.Cell  当前编辑单元格
        */
        complete: null,
        /*在单元格编辑器设置为焦点时执行，如果需要自定义编辑器焦点状态，可以重写该方法
        @cell:fly.ui.grid.Cell  当前编辑单元格
        @box:fly.ui.Element 单元格编辑器控件
        */
        focus: $.falseFun,
        /*关闭编辑器
        @cell:fly.ui.grid.Cell  当前编辑单元格
        */
        close: function (cell) {
            if (cell.editorBox)
                cell.editorBox.destroy();
            cell.el.empty()
            cell.render()
        },
        /*获取单元格值
        @cell:fly.ui.grid.Cell 单元格
        @return :Object 单元格值
        */
        get: function (cell) {
            return cell.editorBox ? cell.editorBox.val() : cell.row.record[this.column.dataIndex];
        },

        /*呈现编辑器视图
        @value:Object 单元格值
        @cell :fly.ui.grid.Cell 单元格
        */
        renderer: function (v, cell) {
            var box = $('<input class="f-grid-editor-text f-grid-editor-box" />')
            cell.el.empty().append(box)
            box.val(v);
            cell.editorBox = box
        }
    })

    /*#C path:fly.ui.grid.plugins.Editing.TextEditor
    GridPanel单元格编辑器:文本编辑器
    @config:JSON 初始化配置
    @base:fly.ui.grid.plugins.Editing.BaseEditor */
    editing.TextEditor = $.Class({
        base: editing.BaseEditor,
        focus: function (cell, box) {
            box.focus().call('select');
        }
    })

    /*#C path:fly.ui.grid.plugins.Editing.IListEditor
    GridPanel单元格列表编辑器接口*/
    editing.IListEditor = {
        items: null,
        /*绑定列表时数据源中提供值的属性名*/
        valueProperty: 0,
        /*绑定列表时数据源中提供文本的属性名*/
        textProperty: 1,
        /*多选时值的分隔符，默认“,”*/
        valueSeparator: ',',
        /*String 编辑框Html标签，默认“div”*/
        tagName: 'div',
        /*String 编辑框格式化模板*/
        boxFormat: '<{1} class="f-grid-editor-{0} f-grid-editor-box" ></{1}>',
        /*String 列表类型*/
        listType: '',
        /*String 列表项格式化模板*/
        itemFormat: null,
        /*为单元格编辑器生成列表项
        @value:Object 单元格值
        @cell: fly.ui.grid.Cell 单元格 */
        createItems: function (v, cell) {
            var cid = dh.getUniqueId(cell)
            var items = this.items;
            var isArr = $.likeArray(items)
            if (!this.itemsRebuilded && isArr && !$.isObject(items[0]) && !$.isArray(items[0]))
                this.items = items.select("o=>[o,o]");
            this.itemsRebuilded = true;

            return $c.IList.select.call(this.items, function (item, i) {
                var t = isArr ? item[this.textProperty] : item, v = isArr ? item[this.valueProperty] : i
                return this.itemFormat.format(t, v == null ? t : v, cid, cid + '_' + i, item)
            }, this).join(' ')
        },
        renderer: function (v, cell) {
            var box = $(this.boxFormat.format(this.listType, this.tagName)).append($(this.createItems(v, cell)))
            cell.el.empty().append(box)
            cell.editorBox = box
            this.set(v, cell);
        },
        /*获取单元格值
        @cell:fly.ui.grid.Cell 单元格
        @return :Object 单元格值
        */
        get: function (cell) {
            if (cell.editorBox) {
                var cs = cell.editorBox.find(":checked,:selected")
                return this.valueSeparator == null ? cs.val() : cs.select('o=>o.value').join(this.valueSeparator)
            }
            return cell.row.record[this.column.dataIndex]
        },
        /*设置单元格值
        @value:Object 单元格值
        @cell:fly.ui.grid.Cell 单元格
        */
        set: function (v, cell) {
            $.each(cell.editorBox[0].children, function (o) {
                if (o.value != null)
                    if (this.valueSeparator == null ? o.value == v : (v.toString() || '').contains(o.value, false, this.valueSeparator))
                        o.checked = o.selected = true;
            }, this)
        }
    }

    /*#C path:fly.ui.grid.plugins.Editing.RadioEditor
    GridPanel单元格编辑器:单选框编辑器
    @config:JSON 初始化配置
    @base:fly.ui.grid.plugins.Editing.BaseEditor */
    editing.RadioEditor = $.Class({
        base: editing.BaseEditor,
        overrides: editing.IListEditor,
        /*String 列表类型：radio*/
        listType: 'radio',
        itemFormat: '<input type=radio value="{1}" name="{2}" id="{3}" /><label for="{3}" >{0}</label> '
    })
    editing.RadioEditor.prototype.valueSeparator = null

    /*#C path:fly.ui.grid.plugins.Editing.CheckEditor
    GridPanel单元格编辑器:复选框编辑器
    @config:JSON 初始化配置
    @base:fly.ui.grid.plugins.Editing.BaseEditor */
    editing.CheckEditor = $.Class({
        base: editing.BaseEditor,
        overrides: editing.IListEditor,
        /*String 列表类型：check*/
        listType: 'check',
        itemFormat: '<input type=checkbox value="{1}" name="{2}" id="{3}" /><label for="{3}" >{0}</label> '
    })

    /*#C path:fly.ui.grid.plugins.Editing.SelectEditor
    GridPanel单元格编辑器:下拉列表编辑器
    @config:JSON 初始化配置
    @base:fly.ui.grid.plugins.Editing.BaseEditor */
    editing.SelectEditor = $.Class({
        base: editing.BaseEditor,
        overrides: editing.IListEditor,
        /*String 列表类型：select*/
        listType: 'select',
        /*String 编辑框Html标签：select*/
        tagName: 'select',
        valueSeparator: null,
        itemFormat: '<option value="{1}" >{0}</option> '
    })

    /*#C path:fly.ui.grid.plugins.Editing.ListEditor
    GridPanel单元格编辑器:多选列表编辑器
    @config:JSON 初始化配置
    @base:fly.ui.grid.plugins.Editing.SelectEditor */
    editing.ListEditor = $.Class({
        base: editing.SelectEditor,
        listType: 'select',
        tagName: 'select',
        valueSeparator: ',',
        boxFormat: '<{1} multiple=multiple class="f-grid-editor-{0} f-grid-editor-box" ></{1}>'
    })

    editing.Editors = {
        string: editing.TextEditor,
        check: editing.CheckEditor,
        radio: editing.RadioEditor
    }
})

